package com.xm.concurrent.base;

import com.xm.concurrent.base.util.SleepUtils;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 4.3.2 等待/通知 机制
 *
 * @author xiaoming
 * @date 2021-05-25 23:39
 */
public class WaitNotify {
    public static void main(String[] args) {
        Thread waitThread = new Thread(new Wait(), "WaitThread");
        waitThread.start();

        SleepUtils.second(1);

        Thread notifyThread = new Thread(new Notify(), "NotifyThread");
        notifyThread.start();

    }

    static boolean flag = true;
    static Object lock = new Object();

    static class Wait implements Runnable {
        @Override
        public void run() {
            // 加锁, 拥有 lock 的 Monitor
            synchronized (lock) {
                // 条件不满足时, 继续 wait ,同事释放 lock 锁
                while (flag) {
                    try {
                        System.out.println(Thread.currentThread() + " flag is true. wait @"
                                + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                        // 线程等待, 释放锁, RUNNING -> WAITING
                        lock.wait();
                    } catch (InterruptedException e) {

                    }
                }
                // 条件满足, 完成工作
                System.out.println(Thread.currentThread() + " flag is false, running @"
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));

            }
        }
    }

    static class Notify implements Runnable {

        @Override
        public void run() {
            synchronized (lock) {
                // 获取锁, 然后进行通知 ( 通知时不释放锁)
                // 直到释放 lock 后, WaitThread 才能从 wait 方法中返回
                System.out.println(Thread.currentThread() + " hold lock. notify @ "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                // 使用时需要先对对象加锁
                lock.notifyAll();
                flag = false;
                SleepUtils.second(5);
            }

            // 再次加锁
            synchronized (lock) {
                System.out.println(Thread.currentThread() + " hold lock again. sleep @ "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                SleepUtils.second(5);
            }

        }
    }
}
